#pragma once

#include <cftc/reflect/object.h>
#include <cftf/meta/table.h>

namespace mt
{

    class GameObjectInfo : public cftc::reflect::Object, public cftf::meta::Table<GameObjectInfo, unsigned int>
    {
        CFT_DECLARE_REFLECT_CLASS();
    public:
        unsigned int  id = 0;
        unsigned int  type = 0;
        unsigned int  displayId = 0;
        std::string name;
        unsigned int  faction = 0;
        unsigned int  flags = 0;
        float   size = 0;
        union                                                   // different GO types have different data field
        {
            // 0 GAMEOBJECT_TYPE_DOOR
            struct
            {
                unsigned int startOpen = 0;                               // 0 used client side to determine GO_ACTIVATED means open/closed
                unsigned int lockId = 0;                                  // 1 -> Lock.dbc
                unsigned int autoCloseTime = 0;                           // 2 secs till autoclose = autoCloseTime / 0x10000
                unsigned int noDamageImmune = 0;                          // 3 break opening whenever you recieve damage?
                unsigned int openTextID = 0;                              // 4 can be used to replace castBarCaption?
                unsigned int closeTextID = 0;                             // 5
            } door;
            // 1 GAMEOBJECT_TYPE_BUTTON
            struct
            {
                unsigned int startOpen = 0;                               // 0
                unsigned int lockId = 0;                                  // 1 -> Lock.dbc
                unsigned int autoCloseTime = 0;                           // 2 secs till autoclose = autoCloseTime / 0x10000
                unsigned int linkedTrapId = 0;                            // 3
                unsigned int noDamageImmune = 0;                          // 4 isBattlegroundObject
                unsigned int large = 0;                                   // 5
                unsigned int openTextID = 0;                              // 6 can be used to replace castBarCaption?
                unsigned int closeTextID = 0;                             // 7
                unsigned int losOK = 0;                                   // 8
            } button;
            // 2 GAMEOBJECT_TYPE_QUESTGIVER
            struct
            {
                unsigned int lockId = 0;                                  // 0 -> Lock.dbc
                unsigned int questList = 0;                               // 1
                unsigned int pageMaterial = 0;                            // 2
                unsigned int gossipID = 0;                                // 3
                unsigned int customAnim = 0;                              // 4
                unsigned int noDamageImmune = 0;                          // 5
                unsigned int openTextID = 0;                              // 6 can be used to replace castBarCaption?
                unsigned int losOK = 0;                                   // 7
                unsigned int allowMounted = 0;                            // 8
                unsigned int large = 0;                                   // 9
            } questgiver;
            // 3 GAMEOBJECT_TYPE_CHEST
            struct
            {
                unsigned int lockId = 0;                                  // 0 -> Lock.dbc
                unsigned int lootId = 0;                                  // 1
                unsigned int chestRestockTime = 0;                        // 2
                unsigned int consumable = 0;                              // 3
                unsigned int minSuccessOpens = 0;                         // 4
                unsigned int maxSuccessOpens = 0;                         // 5
                unsigned int eventId = 0;                                 // 6 lootedEvent
                unsigned int linkedTrapId = 0;                            // 7
                unsigned int questId = 0;                                 // 8 not used currently but store quest required for GO activation for player
                unsigned int level = 0;                                   // 9
                unsigned int losOK = 0;                                   // 10
                unsigned int leaveLoot = 0;                               // 11
                unsigned int notInCombat = 0;                             // 12
                unsigned int logLoot = 0;                                 // 13
                unsigned int openTextID = 0;                              // 14 can be used to replace castBarCaption?
                unsigned int groupLootRules = 0;                          // 15
            } chest;
            // 4 GAMEOBJECT_TYPE_BINDER - empty
            // 5 GAMEOBJECT_TYPE_GENERIC
            struct
            {
                unsigned int floatingTooltip = 0;                         // 0
                unsigned int highlight = 0;                               // 1
                unsigned int serverOnly = 0;                              // 2
                unsigned int large = 0;                                   // 3
                unsigned int floatOnWater = 0;                            // 4
                unsigned int questID = 0;                                 // 5
            } _generic;
            // 6 GAMEOBJECT_TYPE_TRAP
            struct
            {
                unsigned int lockId = 0;                                  // 0 -> Lock.dbc
                unsigned int level = 0;                                   // 1
                unsigned int radius = 0;                                  // 2 radius for trap activation
                unsigned int spellId = 0;                                 // 3
                unsigned int charges = 0;                                 // 4 need respawn (if > 0)
                unsigned int cooldown = 0;                                // 5 time in secs
                unsigned int autoCloseTime = 0;                           //6 secs till autoclose = autoCloseTime / IN_MILLISECONDS (previous was 0x10000)
                unsigned int startDelay = 0;                              // 7
                unsigned int serverOnly = 0;                              // 8
                unsigned int stealthed = 0;                               // 9
                unsigned int large = 0;                                   // 10
                unsigned int stealthAffected = 0;                         // 11
                unsigned int openTextID = 0;                              // 12 can be used to replace castBarCaption?
                unsigned int closeTextID = 0;                             // 13
            } trap;
            // 7 GAMEOBJECT_TYPE_CHAIR
            struct
            {
                unsigned int slots = 0;                                   // 0
                unsigned int height = 0;                                  // 1
                unsigned int onlyCreatorUse = 0;                          // 2
            } chair;
            // 8 GAMEOBJECT_TYPE_SPELL_FOCUS
            struct
            {
                unsigned int focusId = 0;                                 // 0
                unsigned int dist = 0;                                    // 1
                unsigned int linkedTrapId = 0;                            // 2
                unsigned int serverOnly = 0;                              // 3
                unsigned int questID = 0;                                 // 4
                unsigned int large = 0;                                   // 5
            } spellFocus;
            // 9 GAMEOBJECT_TYPE_TEXT
            struct
            {
                unsigned int pageID = 0;                                  // 0
                unsigned int language = 0;                                // 1
                unsigned int pageMaterial = 0;                            // 2
                unsigned int allowMounted = 0;                            // 3
            } text;
            // 10 GAMEOBJECT_TYPE_GOOBER
            struct
            {
                unsigned int lockId = 0;                                  // 0 -> Lock.dbc
                unsigned int questId = 0;                                 // 1
                unsigned int eventId = 0;                                 // 2
                unsigned int autoCloseTime = 0;                           //3 secs till autoclose = autoCloseTime / IN_MILLISECONDS (previous was 0x10000)
                unsigned int customAnim = 0;                              // 4
                unsigned int consumable = 0;                              // 5
                unsigned int cooldown = 0;                                // 6
                unsigned int pageId = 0;                                  // 7
                unsigned int language = 0;                                // 8
                unsigned int pageMaterial = 0;                            // 9
                unsigned int spellId = 0;                                 // 10
                unsigned int noDamageImmune = 0;                          // 11
                unsigned int linkedTrapId = 0;                            // 12
                unsigned int large = 0;                                   // 13
                unsigned int openTextID = 0;                              // 14 can be used to replace castBarCaption?
                unsigned int closeTextID = 0;                             // 15
                unsigned int losOK = 0;                                   // 16 isBattlegroundObject
                unsigned int allowMounted = 0;                            // 17
                unsigned int floatingTooltip = 0;                         // 18
                unsigned int gossipID = 0;                                // 19
            } goober;
            // 11 GAMEOBJECT_TYPE_TRANSPORT
            struct
            {
                unsigned int pause = 0;                                   // 0
                unsigned int startOpen = 0;                               // 1
                unsigned int autoCloseTime = 0;                           //2 secs till autoclose = autoCloseTime / IN_MILLISECONDS (previous was 0x10000)
            } transport;
            // 12 GAMEOBJECT_TYPE_AREADAMAGE
            struct
            {
                unsigned int lockId = 0;                                  // 0
                unsigned int radius = 0;                                  // 1
                unsigned int damageMin = 0;                               // 2
                unsigned int damageMax = 0;                               // 3
                unsigned int damageSchool = 0;                            // 4
                unsigned int autoCloseTime = 0;                           //5 secs till autoclose = autoCloseTime / IN_MILLISECONDS (previous was 0x10000)
                unsigned int openTextID = 0;                              // 6
                unsigned int closeTextID = 0;                             // 7
            } areadamage;
            // 13 GAMEOBJECT_TYPE_CAMERA
            struct
            {
                unsigned int lockId = 0;                                  // 0 -> Lock.dbc
                unsigned int cinematicId = 0;                             // 1
                unsigned int eventID = 0;                                 // 2
                unsigned int openTextID = 0;                              // 3 can be used to replace castBarCaption?
            } camera;
            // 14 GAMEOBJECT_TYPE_MAPOBJECT - empty
            // 15 GAMEOBJECT_TYPE_MO_TRANSPORT
            struct
            {
                unsigned int taxiPathId = 0;                              // 0
                unsigned int moveSpeed = 0;                               // 1
                unsigned int accelRate = 0;                               // 2
                unsigned int startEventID = 0;                            // 3
                unsigned int stopEventID = 0;                             // 4
                unsigned int transportPhysics = 0;                        // 5
                unsigned int mapID = 0;                                   // 6
            } moTransport;
            // 16 GAMEOBJECT_TYPE_DUELFLAG - empty
            // 17 GAMEOBJECT_TYPE_FISHINGNODE
            struct
            {
                unsigned int _data0 = 0;                                  // 0
                unsigned int lootId = 0;                                  // 1
            } fishnode;
            // 18 GAMEOBJECT_TYPE_SUMMONING_RITUAL
            struct
            {
                unsigned int reqParticipants = 0;                         // 0
                unsigned int spellId = 0;                                 // 1
                unsigned int animSpell = 0;                               // 2
                unsigned int ritualPersistent = 0;                        // 3
                unsigned int casterTargetSpell = 0;                       // 4
                unsigned int casterTargetSpellTargets = 0;                // 5
                unsigned int castersGrouped = 0;                          // 6
                unsigned int ritualNoTargetCheck = 0;                     // 7
            } summoningRitual;
            // 19 GAMEOBJECT_TYPE_MAILBOX - empty
            // 20 GAMEOBJECT_TYPE_AUCTIONHOUSE
            struct
            {
                unsigned int actionHouseID = 0;                           // 0
            } auctionhouse;
            // 21 GAMEOBJECT_TYPE_GUARDPOST
            struct
            {
                unsigned int creatureID = 0;                              // 0
                unsigned int charges = 0;                                 // 1
            } guardpost;
            // 22 GAMEOBJECT_TYPE_SPELLCASTER
            struct
            {
                unsigned int spellId = 0;                                 // 0
                unsigned int charges = 0;                                 // 1
                unsigned int partyOnly = 0;                               // 2
            } spellcaster;
            // 23 GAMEOBJECT_TYPE_MEETINGSTONE
            struct
            {
                unsigned int minLevel = 0;                                // 0
                unsigned int maxLevel = 0;                                // 1
                unsigned int areaID = 0;                                  // 2
            } meetingstone;
            // 24 GAMEOBJECT_TYPE_FLAGSTAND
            struct
            {
                unsigned int lockId = 0;                                  // 0
                unsigned int pickupSpell = 0;                             // 1
                unsigned int radius = 0;                                  // 2
                unsigned int returnAura = 0;                              // 3
                unsigned int returnSpell = 0;                             // 4
                unsigned int noDamageImmune = 0;                          // 5
                unsigned int openTextID = 0;                              // 6
                unsigned int losOK = 0;                                   // 7
            } flagstand;
            // 25 GAMEOBJECT_TYPE_FISHINGHOLE
            struct
            {
                unsigned int radius = 0;                                  // 0 how close bobber must land for sending loot
                unsigned int lootId = 0;                                  // 1
                unsigned int minSuccessOpens = 0;                         // 2
                unsigned int maxSuccessOpens = 0;                         // 3
                unsigned int lockId = 0;                                  // 4 -> Lock.dbc; possibly 1628 for all?
            } fishinghole;
            // 26 GAMEOBJECT_TYPE_FLAGDROP
            struct
            {
                unsigned int lockId = 0;                                  // 0
                unsigned int eventID = 0;                                 // 1
                unsigned int pickupSpell = 0;                             // 2
                unsigned int noDamageImmune = 0;                          // 3
                unsigned int openTextID = 0;                              // 4
            } flagdrop;
            // 27 GAMEOBJECT_TYPE_MINI_GAME
            struct
            {
                unsigned int gameType = 0;                                // 0
            } miniGame;
            // 29 GAMEOBJECT_TYPE_CAPTURE_POINT
            struct
            {
                unsigned int radius = 0;                                  // 0
                unsigned int spell = 0;                                   // 1
                unsigned int worldState1 = 0;                             // 2
                unsigned int worldState2 = 0;                             // 3
                unsigned int winEventID1 = 0;                             // 4
                unsigned int winEventID2 = 0;                             // 5
                unsigned int contestedEventID1 = 0;                       // 6
                unsigned int contestedEventID2 = 0;                       // 7
                unsigned int progressEventID1 = 0;                        // 8
                unsigned int progressEventID2 = 0;                        // 9
                unsigned int neutralEventID1 = 0;                         // 10
                unsigned int neutralEventID2 = 0;                         // 11
                unsigned int neutralPercent = 0;                          // 12
                unsigned int worldState3 = 0;                             // 13
                unsigned int minSuperiority = 0;                          // 14
                unsigned int maxSuperiority = 0;                          // 15
                unsigned int minTime = 0;                                 // 16
                unsigned int maxTime = 0;                                 // 17
                unsigned int large = 0;                                   // 18
                unsigned int highlight = 0;                               // 19
            } capturePoint;
            // 30 GAMEOBJECT_TYPE_AURA_GENERATOR
            struct
            {
                unsigned int startOpen = 0;                               // 0
                unsigned int radius = 0;                                  // 1
                unsigned int auraID1 = 0;                                 // 2
                unsigned int conditionID1 = 0;                            // 3
                unsigned int auraID2 = 0;                                 // 4
                unsigned int conditionID2 = 0;                            // 5
                unsigned int serverOnly = 0;                              // 6
            } auraGenerator;

            // not use for specific field access (only for output with loop by all filed), also this determinate max union size
            struct
            {
                unsigned int data[24] = {0};
            } raw;
        };

        unsigned int MinMoneyLoot = 0;
        unsigned int MaxMoneyLoot = 0;
        //unsigned int ScriptId;

        // helpers
        bool IsDespawnAtAction() const
        {
            switch (type)
            {
            case GAMEOBJECT_TYPE_CHEST:  return chest.consumable;
            case GAMEOBJECT_TYPE_GOOBER: return goober.consumable;
            default: return false;
            }
        }

        unsigned int GetLockId() const
        {
            switch (type)
            {
            case GAMEOBJECT_TYPE_DOOR:       return door.lockId;
            case GAMEOBJECT_TYPE_BUTTON:     return button.lockId;
            case GAMEOBJECT_TYPE_QUESTGIVER: return questgiver.lockId;
            case GAMEOBJECT_TYPE_CHEST:      return chest.lockId;
            case GAMEOBJECT_TYPE_TRAP:       return trap.lockId;
            case GAMEOBJECT_TYPE_GOOBER:     return goober.lockId;
            case GAMEOBJECT_TYPE_AREADAMAGE: return areadamage.lockId;
            case GAMEOBJECT_TYPE_CAMERA:     return camera.lockId;
            case GAMEOBJECT_TYPE_FLAGSTAND:  return flagstand.lockId;
            case GAMEOBJECT_TYPE_FISHINGHOLE: return fishinghole.lockId;
            case GAMEOBJECT_TYPE_FLAGDROP:   return flagdrop.lockId;
            default: return 0;
            }
        }

        bool GetDespawnPossibility() const                      // despawn at targeting of cast?
        {
            switch (type)
            {
            case GAMEOBJECT_TYPE_DOOR:       return door.noDamageImmune;
            case GAMEOBJECT_TYPE_BUTTON:     return button.noDamageImmune;
            case GAMEOBJECT_TYPE_QUESTGIVER: return questgiver.noDamageImmune;
            case GAMEOBJECT_TYPE_GOOBER:     return goober.noDamageImmune;
            case GAMEOBJECT_TYPE_FLAGSTAND:  return flagstand.noDamageImmune;
            case GAMEOBJECT_TYPE_FLAGDROP:   return flagdrop.noDamageImmune;
            default: return true;
            }
        }

        unsigned int GetCharges() const                               // despawn at uses amount
        {
            switch (type)
            {
            case GAMEOBJECT_TYPE_TRAP:        return trap.charges;
            case GAMEOBJECT_TYPE_GUARDPOST:   return guardpost.charges;
            case GAMEOBJECT_TYPE_SPELLCASTER: return spellcaster.charges;
            default: return 0;
            }
        }

        unsigned int GetCooldown() const                              // not triggering at detection target or use until coolodwn expire
        {
            switch (type)
            {
            case GAMEOBJECT_TYPE_TRAP:        return trap.cooldown;
            case GAMEOBJECT_TYPE_GOOBER:      return goober.cooldown;
            default: return 0;
            }
        }

        unsigned int GetLinkedGameObjectEntry() const
        {
            switch (type)
            {
            case GAMEOBJECT_TYPE_BUTTON:      return button.linkedTrapId;
            case GAMEOBJECT_TYPE_CHEST:       return chest.linkedTrapId;
            case GAMEOBJECT_TYPE_SPELL_FOCUS: return spellFocus.linkedTrapId;
            case GAMEOBJECT_TYPE_GOOBER:      return goober.linkedTrapId;
            default: return 0;
            }
        }

        unsigned int GetAutoCloseTime() const
        {
            unsigned int autoCloseTime = 0;
            switch (type)
            {
            case GAMEOBJECT_TYPE_DOOR:          autoCloseTime = door.autoCloseTime; break;
            case GAMEOBJECT_TYPE_BUTTON:        autoCloseTime = button.autoCloseTime; break;
            case GAMEOBJECT_TYPE_TRAP:          autoCloseTime = trap.autoCloseTime; break;
            case GAMEOBJECT_TYPE_GOOBER:        autoCloseTime = goober.autoCloseTime; break;
            case GAMEOBJECT_TYPE_TRANSPORT:     autoCloseTime = transport.autoCloseTime; break;
            case GAMEOBJECT_TYPE_AREADAMAGE:    autoCloseTime = areadamage.autoCloseTime; break;
            default: break;
            }
            return autoCloseTime / 0x10000;
        }

        unsigned int GetLootId() const
        {
            switch (type)
            {
            case GAMEOBJECT_TYPE_CHEST:       return chest.lootId;
            case GAMEOBJECT_TYPE_FISHINGHOLE: return fishinghole.lootId;
            default: return 0;
            }
        }

        unsigned int GetGossipMenuId() const
        {
            switch (type)
            {
            case GAMEOBJECT_TYPE_QUESTGIVER:    return questgiver.gossipID;
            case GAMEOBJECT_TYPE_GOOBER:        return goober.gossipID;
            default: return 0;
            }
        }
    };

}